#ifndef _COMMON_H
#define _COMMON_H

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define T_IDENTIFIER_LEN 32

#define T_ERROR_MALLOC(p) \
{\
	if ((p) == NULL) {\
		perror("malloc()");\
		exit(1);\
	}\
}

#define T_ERROR_IDNOTFOUND(s) \
{\
	fprintf(stderr, "identifier [%s] not found\n", (s));\
	exit(1);\
}

#define T_ERROR_IDDUPLICATE(s) \
{\
	fprintf(stderr, "identifier [%s] duplicate\n", (s));\
	exit(1);\
}

#define T_ERROR_NOTINLOOP() \
{\
	fprintf(stderr, "statement allowed only in loop context\n");\
	exit(1);\
}

#define T_ERROR_INFUNCTION() \
{\
	fprintf(stderr, "statement not allowed in function context\n");\
	exit(1);\
}

#define T_ERROR_TYPENOTCOMP() \
{\
	fprintf(stderr, "type not compatible\n");\
	exit(1);\
}

#define T_ERROR_NONZERO(x) \
{\
	if (x == 0) {\
		fprintf(stderr, "non-zero value expected\n");\
		exit(1);\
	}\
}

#define T_LIST_INIT(ListType) \
{\
	ListType *_l;\
\
	_l = malloc(sizeof(ListType));\
	T_ERROR_MALLOC(_l);\
\
	_l->count = 0;\
	_l->first = NULL;\
\
	return _l;\
}

#define T_LIST_INIT_ADD(ListType, NodeType, ElementField, ElementName) \
{\
	ListType *_l;\
\
	_l = malloc(sizeof(ListType));\
	T_ERROR_MALLOC(_l);\
\
	_l->count = 1;\
\
	_l->first = malloc(sizeof(NodeType));\
	T_ERROR_MALLOC(_l->first);\
\
	_l->first->ElementField = (ElementName);\
	_l->first->next = NULL;\
\
	return _l;\
}

#define T_LIST_ADD(ListName, NodeType, ElementField, ElementName) \
{\
	NodeType *_n, *_z;\
\
	_n = malloc(sizeof(NodeType));\
	T_ERROR_MALLOC(_n);\
\
	_n->ElementField = (ElementName);\
	_n->next = NULL;\
\
	if ((ListName)->first == NULL)\
		(ListName)->first = _n;\
	else {\
		for (_z = (ListName)->first; _z->next != NULL; _z = _z->next);\
		_z->next = _n;\
	}\
\
	(ListName)->count++;\
\
	return (ListName);\
}

#define T_LIST_COMBINE(List1, List2, NodeType) \
{\
	NodeType *_z;\
\
	if ((List1)->first == NULL)\
		(List1)->first = (List2)->first;\
	else {\
		for (_z = (List1)->first; _z->next != NULL; _z = _z->next);\
		_z->next = (List2)->first;\
	}\
\
	(List1)->count += (List2)->count;\
\
	free(List2);\
\
	return (List1);\
}

#define T_IDENTIFIER_COPY(D, S) \
{\
	strncpy((D), (S), T_IDENTIFIER_LEN - 1);\
	(D)[T_IDENTIFIER_LEN - 1] = '\0';\
}

#define T_IDENTIFIER_CMP(A, B) \
(strncmp((A), (B), T_IDENTIFIER_LEN - 1))

#endif
